package com.woniu.config;

import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.reactor.filter.SaTokenContextFilterForReactor;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.server.WebFilter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author pml
 * @Date 2025/6/13 17:28
 * @Description TODO
 * SaToken配置类
 * 注册拦截器并配置拦截规则，实现全局登录校验
 * 这样配置后无需在每个接口单独添加@SaCheckLogin注解
 */
@Configuration
public class SaTokenConfig implements WebFluxConfigurer {
    /**
     * 注册Sa-Token上下文过滤器，优先级最高，保证token上下文不丢失
     * 为什么@Order(Ordered.HIGHEST_PRECEDENCE)？确保最先执行，防止被其他过滤器覆盖
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public WebFilter saTokenContextFilterForReactor() {
        return new SaTokenContextFilterForReactor();
    }

    /**
     * 注册Sa-Token主过滤器（WebFlux专用）
     * 为什么用SaReactorFilter？WebFlux不支持SpringMVC的Interceptor，必须使用Reactive Filter
     */
    @Bean
    public SaReactorFilter saReactorFilter() {
        return new SaReactorFilter()
                // 拦截路由：所有路径
                .addInclude("/**")
                // 排除路由：登录、登出接口和错误页
                .addExclude("/login")
                .addExclude("/logout")
                .addExclude("/range/uploadTargetRange")
                .addExclude("/ctfContainer/**")
                .addExclude("/refreshToken")  // 新增：排除刷新令牌接口
                .addExclude("/error")
                .addExclude("/register/**")
                .addExclude("/sms/**")
                .addExclude("/userStatistics/**")//放行首页折线图和饼状图
                .addExclude("/ctfcontest/searchByUserName")//放行首页折线图
                .addExclude("/alluser/textMessageLogin")//放行短信发送
                .addExclude("/sms/**")//放行短信登录

//                .addExclude("/ai/chat")
                // 认证函数：每次请求执行
                .setAuth(obj -> {
                    // 登录校验：除排除路径外均需要登录
                    SaRouter.match("/**", auth -> StpUtil.checkLogin());
                })
                // 异常处理函数：认证失败时执行
                .setError(e -> {
                    // 返回标准化JSON错误响应，与前端错误处理逻辑保持一致
                    return SaResult.error("未登录或token已过期，请重新登录").setCode(401);
                });
    }
    /**
     * CORS 跨域处理策略
     */
    @Bean
    public SaCorsHandleFunction corsHandle() {
        return (req, res, sto) -> {
            // 获得客户端domain
            String origin = req.getHeader("Origin");
            if (origin == null) {
                origin = req.getHeader("Referer");
            }

            // ---------- 设置跨域响应头 ----------
            res
                    // 允许第三方 Cookie
                    .setHeader("Access-Control-Allow-Credentials", "true")
                    // 允许指定域访问跨域资源
                    .setHeader("Access-Control-Allow-Origin", origin)
                    // 允许所有请求方式
                    .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
                    // 允许的header参数
                    .setHeader("Access-Control-Allow-Headers", "x-requested-with,satoken")
                    // 有效时间
                    .setHeader("Access-Control-Max-Age", "3600")
            ;

            // 如果是预检请求，则立即返回到前端
            SaRouter.match(SaHttpMethod.OPTIONS)
                    .free(r -> System.out.println("--------OPTIONS预检请求，不做处理"))
                    .back();
        };
    }
}
